﻿using System;
using UniRx;
using UniRx.Operators;

/// <summary>
/// Update 固定器
/// </summary>
public class FixObservable : OperatorObservableBase<long>
{
    private readonly IObservable<long> m_Source;

    public FixObservable(IObservable<long> source)
        : base(source.IsRequiredSubscribeOnCurrentThread())
    {
        m_Source = source;
    }

    protected override IDisposable SubscribeCore(IObserver<long> observer, IDisposable cancel)
    {
        return new SourceObserver(this, observer, cancel).Run();
    }

    internal class SourceObserver : OperatorObserverBase<long, long>
    {
        private readonly FixObservable m_Parent;
        private readonly IObservable<long> m_Target;
        private object m_Gate = new object();
        private long param;

        public SourceObserver(FixObservable parnet, IObserver<long> observer, IDisposable cancel) : base(observer, cancel)
        {
            m_Parent = parnet;
            m_Target = Observable.EveryFixedUpdate().Select(_ => param);
        }

        public IDisposable Run()
        {
            var sourceSubscription = m_Parent.m_Source.Subscribe(this);
            var targetSubscription = m_Target.Subscribe(observer);

            return StableCompositeDisposable.Create(sourceSubscription, targetSubscription);
        }

        public override void OnNext(long value)
        {
            lock (m_Gate)
            {
                param = value;
            }
        }

        public override void OnCompleted()
        {
            lock (m_Gate)
            {
                try { observer.OnCompleted(); } finally { Dispose(); }
            }
        }

        public override void OnError(Exception error)
        {
            lock (m_Gate)
            {
                try { observer.OnError(error); } finally { Dispose(); }
            }
        }
    }
}